package com.test.webapp.action;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.converters.IntegerConverter;
import org.apache.commons.beanutils.converters.LongConverter;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.Globals;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.actions.DispatchAction;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.test.Constants;
import com.test.util.ConvertUtil;
import com.test.util.CurrencyConverter;
import com.test.util.DateConverter;
import com.test.util.ObjectUtils;
import com.test.util.Pagination;
import com.test.util.PaginationUrl;
import com.test.util.SoftPagination;
import com.test.util.SoftPaginationUrl;
import com.test.util.SqlInjectionFilter;

@SuppressWarnings("unchecked")
public class BaseAction extends DispatchAction {

	private static final Long defaultLong = null;

	private static final String PAGE = "page"; // 分页获取的属性

	static {
		ConvertUtils.register(new CurrencyConverter(), Double.class);
		ConvertUtils.register(new DateConverter(), Date.class);
		ConvertUtils.register(new DateConverter(), String.class);
		ConvertUtils.register(new LongConverter(defaultLong), Long.class);
		ConvertUtils.register(new IntegerConverter(defaultLong), Integer.class);
	}

	protected final Log log = LogFactory.getLog(getClass());

	/**
	 * @see com.eport.ghostforest.util.ConvertUtil#convert(java.lang.Object)
	 */
	protected Object convert(Object o) throws Exception {
		return ConvertUtil.convert(o);
	}

	/**
	 * @see com.eport.ghostforest.util.ConvertUtil#convertLists(java.lang.Object)
	 */
	protected Object convertLists(Object o) throws Exception {
		return ConvertUtil.convertLists(o);
	}

	/**
	 * encode字符串解码<br>
	 * 
	 * @param chinese
	 *            字符串
	 * @param code
	 *            编码
	 * @return
	 */
	@SuppressWarnings("unused")
	public String decode(String str, String code) throws UnsupportedEncodingException {
		String newStr = null;
		try {
			newStr = URLDecoder.decode(str, code);
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		return newStr;
	}

	/**
	 * encode字符串编码<br>
	 * 
	 * @param chinese
	 *            字符串
	 * @param code
	 *            编码
	 * @return
	 */
	public String encode(String str, String code) {
		String newStr = null;
		try {
			newStr = URLEncoder.encode(str, code);
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		return newStr;
	}

	/**
	 * Override the execute method in DispatchAction to parse URLs and forward
	 * to methods without parameters.
	 * </p>
	 * <p>
	 * This is based on the following system: <p/>
	 * <ul>
	 * <li>edit*.html -> edit method</li>
	 * <li>save*.html -> save method</li>
	 * <li>view*.html -> search method</li>
	 * </ul>
	 */
	@Override
	public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {

		if (isCancelled(request)) {
			try {
				getMethod("cancel");
				return dispatchMethod(mapping, form, request, response, "cancel");
			}
			catch (NoSuchMethodException n) {
				log.warn("No 'cancel' method found, returning null");
				return cancelled(mapping, form, request, response);
			}
		}

		// Check to see if methodName indicated by request parameter
		String actionMethod = getActionMethodWithMapping(request, mapping);
		log.info("actionMethod : " + actionMethod);

		if (actionMethod != null) {
			return dispatchMethod(mapping, form, request, response, actionMethod);
		} else {
			String[] rules = { "edit", "save", "search", "view" };
			for (int i = 0; i < rules.length; i++) {
				// apply the rules for automatically appending the method name
				if (request.getServletPath().indexOf(rules[i]) > -1) {
					return dispatchMethod(mapping, form, request, response, rules[i]);
				}
			}
		}

		return super.execute(mapping, form, request, response);
	}

	/**
	 * 封装ActionForward<br>
	 * 
	 * @param path
	 * @return
	 */
	protected ActionForward forward(String path) {
		if (StringUtils.isEmpty(path)) {
			return new ActionForward("/error/404.jsp");
		}
		return new ActionForward(path);
	}

	/**
	 * Convenience method for getting an action form base on it's mapped scope.
	 * 
	 * @param mapping
	 *            The ActionMapping used to select this instance
	 * @param request
	 *            The HTTP request we are processing
	 * @return ActionForm the form from the specifies scope, or null if nothing
	 *         found
	 */
	protected ActionForm getActionForm(ActionMapping mapping, HttpServletRequest request) {
		ActionForm actionForm = null;

		// Remove the obsolete form bean
		if (mapping.getAttribute() != null) {
			if ("request".equals(mapping.getScope())) {
				actionForm = (ActionForm) request.getAttribute(mapping.getAttribute());
			} else {
				HttpSession session = request.getSession();
				actionForm = (ActionForm) session.getAttribute(mapping.getAttribute());
			}
		}

		return actionForm;
	}

	/**
	 * Gets the method name based on the prepender passed to it.
	 */
	protected String getActionMethod(HttpServletRequest request, String prepend) {
		String name = null;

		// for backwards compatibility, try with no prepend first
		name = request.getParameter(prepend);
		log.info("name : " + name);
		if (name != null) {
			// trim any whitespace around - this might happen on buttons
			name = name.trim();
			// lowercase first letter
			return name.replace(name.charAt(0), Character.toLowerCase(name.charAt(0)));
		}

		Enumeration e = request.getParameterNames();

		while (e.hasMoreElements()) {
			String currentName = (String) e.nextElement();

			if (currentName.startsWith(prepend + ".")) {
				if (log.isDebugEnabled()) {
					log.debug("calling method: " + currentName);
				}

				String[] parameterMethodNameAndArgs = StringUtils.split(currentName, ".");
				name = parameterMethodNameAndArgs[1];
				break;
			}
		}

		return name;
	}

	/**
	 * Gets the method name based on the mapping passed to it
	 */
	private String getActionMethodWithMapping(HttpServletRequest request, ActionMapping mapping) {
		log.info("mapping.getParameter() : " + mapping.getParameter());
		return getActionMethod(request, mapping.getParameter());
	}

	/**
	 * 封装getAttribute<br>
	 * 
	 * @param request
	 * @param attribute
	 * @return
	 */
	protected Object getAttribute(HttpServletRequest request, String attribute) {
		if (ObjectUtils.isNull(request)) {
			return ObjectUtils.NULL;
		}
		if (StringUtils.isEmpty(attribute)) {
			return ObjectUtils.NULL;
		}
		return request.getAttribute(attribute);
	}

	/**
	 * Convenience method to get Spring-initialized beans
	 * 
	 * @param name
	 * @return Object bean from ApplicationContext
	 */
	public Object getBean(String name) {
		ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servlet.getServletContext());
		return ctx.getBean(name);
	}

	/**
	 * Convenience method to get the Configuration HashMap from the servlet
	 * context.
	 * 
	 * @return the user's populated form from the session
	 */
	public Map getConfiguration() {
		Map config = (HashMap) getServlet().getServletContext().getAttribute((String) Constants.settings.get("CONFIG"));

		// so unit tests don't puke when nothing's been set
		if (config == null) {
			return new HashMap();
		}

		return config;
	}

	/**
	 * Convenience method to initialize messages in a subclass.
	 * 
	 * @param request
	 *            the current request
	 * @return the populated (or empty) messages
	 */
	@Override
	public ActionMessages getMessages(HttpServletRequest request) {
		ActionMessages messages = null;
		HttpSession session = request.getSession();

		if (request.getAttribute(Globals.MESSAGE_KEY) != null) {
			messages = (ActionMessages) request.getAttribute(Globals.MESSAGE_KEY);
			saveMessages(request, messages);
		} else if (session.getAttribute(Globals.MESSAGE_KEY) != null) {
			messages = (ActionMessages) session.getAttribute(Globals.MESSAGE_KEY);
			saveMessages(request, messages);
			session.removeAttribute(Globals.MESSAGE_KEY);
		} else {
			messages = new ActionMessages();
		}

		return messages;
	}

	/**
	 * 封装getParameter<br>
	 * 
	 * @param request
	 * @param parameter
	 * @return
	 */
	protected String getParameter(HttpServletRequest request, String parameter) {
		if (ObjectUtils.isNull(request)) {
			return StringUtils.EMPTY;
		}
		if (StringUtils.isEmpty(parameter)) {
			return StringUtils.EMPTY;
		}
		return request.getParameter(parameter);
	}

	/**
	 * 返回集合
	 * 
	 * @param request
	 *            当前请求
	 * @param param
	 *            参数名称
	 * @return
	 */
	protected String[] getParameterValues(HttpServletRequest request, String param) {
		if (StringUtils.isEmpty(param) || ObjectUtils.isNull(request)) {
			return new String[0];
		}
		String[] arrays = request.getParameterValues(param);
		if (ObjectUtils.isNull(arrays)) {
			return new String[0];
		}
		return arrays;
	}

	/**
	 * 封装getSession<br>
	 * 
	 * @param request
	 * @return
	 */
	protected HttpSession getSession(HttpServletRequest request) {
		if (ObjectUtils.isNull(request)) {
			return null;
		}
		return request.getSession();
	}

	/**
	 * 封装invalidate<br>
	 * 
	 * @param session
	 */
	protected void invalidate(HttpSession session) {
		if (ObjectUtils.isNull(session)) {
			return;
		}
		session.invalidate();
	}

	/**
	 * 分页方法(调用此方法时 分页方法 第一个参数必须为Pagination类型的)
	 * 
	 * @param size
	 *            每页信息数量
	 * @param request
	 *            当前请求
	 * @param pageMap
	 *            分页属性集 ?a= &b= &c=...
	 * @param clazz
	 *            分页方法所在类
	 * @param methodName
	 *            分页方法名称
	 * @param object
	 *            分页方法调用对象 null时表示为静态方法
	 * @param params
	 *            分页方法参数
	 * @return
	 * @throws UnsupportedEncodingException
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 * @exp List<Student> list = (List<Student>) page(2, request, pageMap,
	 *      DB.class, "getStudentsByPagination", null, 1, "abc");
	 */
	protected List page(int size, HttpServletRequest request, Map<String, Object> pageMap, Class clazz, String methodName, Object object,
	        Object... params) throws UnsupportedEncodingException, IllegalArgumentException, IllegalAccessException, InvocationTargetException,
	        SecurityException, NoSuchMethodException {

		String page = (String) request.getAttribute(PAGE);
		if (StringUtils.isNumeric(page)) {
			page = request.getParameter(PAGE);
		}
		int currpageNo = 1;
		if (StringUtils.isNumeric(page)) {
			currpageNo = Integer.parseInt(page);
		}
		if (size < 0) {
			size = 0;
		}
		Pagination pagination = new Pagination(currpageNo, size);

		int length = params.length + 1;
		Class[] clazzes = new Class[length];
		clazzes[0] = pagination.getClass();
		for (int i = 1; i < length; i++) {
			clazzes[i] = params[i - 1].getClass();
		}
		// 通过方法名称和参数类型 得到方法
		Method method = clazz.getMethod(methodName, clazzes);
		// 得到方法参数值
		Object[] objects = null;
		if (params == null) {
			objects = new Object[] { pagination };
		} else {
			objects = new Object[length];
			objects[0] = pagination;
			for (int i = 1; i < length; i++) {
				objects[i] = params[i - 1];
			}
		}
		// 执行方法
		List list = (List) method.invoke(object, objects);

		PaginationUrl.replaceNav(pageMap, pagination, request);
		return list;
	}

	/**
	 * 分页方法(调用此方法时 分页方法 第一个参数必须为Pagination类型的)
	 * 
	 * @param size
	 *            每页信息数量
	 * @param request
	 *            当前请求
	 * @param pageMap
	 *            分页属性集 ?a= &b= &c=...
	 * @param method
	 *            分页方法
	 * @param object
	 *            分页方法调用对象 null时表示为静态方法
	 * @param params
	 *            分页方法参数
	 * @return
	 * @throws UnsupportedEncodingException
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @exp Map<String, Object> pageMap = new HashMap<String, Object>();
	 *      pageMap.put("method", "pageByPagination"); Method method
	 *      =DB.class.getMethod("getStudentsByPagination", Pagination.class,
	 *      Integer.class, String.class); List<Student> list = (List<Student>)page(2,
	 *      request, pageMap, method, null, 1, "abc");
	 */
	protected List page(int size, HttpServletRequest request, Map<String, Object> pageMap, Method method, Object object, Object... params)
	        throws UnsupportedEncodingException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {

		request.getParameterMap();
		String page = (String) request.getAttribute(PAGE);
		if (StringUtils.isNumeric(page)) {
			page = request.getParameter(PAGE);
		}
		int currpageNo = 1;
		if (StringUtils.isNumeric(page)) {
			currpageNo = Integer.parseInt(page);
		}
		if (size < 0) {
			size = 0;
		}
		Pagination pagination = new Pagination(currpageNo, size);
		Object[] objects = null;
		if (params == null) {
			objects = new Object[] { pagination };
		} else {
			int length = params.length + 1;
			objects = new Object[length];
			objects[0] = pagination;
			for (int i = 1; i < length; i++) {
				objects[i] = params[i - 1];
			}
		}
		List list = (List) method.invoke(object, objects);
		PaginationUrl.replaceNav(pageMap, pagination, request);
		return list;
	}

	/**
	 * @param response
	 * @param flag
	 *            true成功 false失败
	 * @throws IOException
	 */
	protected void print(HttpServletResponse response, boolean flag) throws IOException {
		StringBuilder builder = new StringBuilder();
		builder.append("{");
		if (flag) {
			builder.append("success:true");
		} else {
			builder.append("success:false");
		}
		builder.append("}");
		try {
			print(response, builder.toString(), null, null);
		}
		catch (IOException e) {
			e.printStackTrace();
			throw new IOException();
		}
	}

	protected void print(HttpServletResponse response, String message, String encoding, String type) throws IOException {
		try {
			if (StringUtils.isEmpty(encoding)) {
				encoding = "utf-8";
			}
			if (StringUtils.isEmpty(type)) {
				type = "text/html;charset=utf-8";
			}
			response.setCharacterEncoding(encoding);
			response.setContentType(type);
			response.getWriter().print(message);
		}
		catch (IOException e) {
			e.printStackTrace();
			throw new IOException();
		}
	}

	/**
	 * 使用Response.getWriter()进行输出<br>
	 * 
	 * @param response
	 * @param message
	 *            打印信息
	 * @param encoding
	 *            编码
	 * @param type
	 *            响应类型
	 * @param params
	 *            参数
	 * @throws IOException
	 * @exp print("{success : %s, message : '%s'}", "utf-8", "text/html;
	 *      charset=utf-8", "abc", "efg");
	 */
	protected void print(HttpServletResponse response, String message, String encoding, String type, Object... params) throws IOException {
		try {
			if (StringUtils.isEmpty(encoding)) {
				encoding = "utf-8";
			}
			if (StringUtils.isEmpty(type)) {
				type = "text/html;charset=utf-8";
			}
			response.setCharacterEncoding(encoding);
			response.setContentType(type);
			response.getWriter().print(String.format(message, params));
		}
		catch (IOException e) {
			e.printStackTrace();
			throw new IOException();
		}
	}

	/**
	 * Convenience method for removing the obsolete form bean.
	 * 
	 * @param mapping
	 *            The ActionMapping used to select this instance
	 * @param request
	 *            The HTTP request we are processing
	 */
	protected void removeFormBean(ActionMapping mapping, HttpServletRequest request) {
		// Remove the obsolete form bean
		if (mapping.getAttribute() != null) {
			if ("request".equals(mapping.getScope())) {
				request.removeAttribute(mapping.getAttribute());
			} else {
				HttpSession session = request.getSession();
				session.removeAttribute(mapping.getAttribute());
			}
		}
	}

	/**
	 * 封装setAttribute<br>
	 * 
	 * @param request
	 * @param attribute
	 * @param value
	 */
	protected void setAttribute(HttpServletRequest request, String attribute, Object value) {
		if (ObjectUtils.isNull(request)) {
			return;
		}
		request.setAttribute(attribute, value);
	}

	/**
	 * 封装setAttribute<br>
	 * 
	 * @param request
	 * @param attribute
	 * @param value
	 */
	protected void setAttribute(HttpSession session, String attribute, Object value) {
		if (ObjectUtils.isNull(session)) {
			return;
		}
		session.setAttribute(attribute, value);
	}

	/**
	 * 此方法参照spring的moduel进行处理 目的减少对setAttribute的使用
	 * 
	 * @param request
	 *            当前请求
	 * @param mapName
	 *            集合名称
	 * @param attributeMap
	 *            属性映射集
	 */
	protected void setAttributeMap(HttpServletRequest request, String mapName, Map<String, Object> attributeMap) {
		if (ObjectUtils.isNull(request)) {
			return;
		}
		if (StringUtils.isEmpty(mapName)) {
			return;
		}
		request.setAttribute(mapName, attributeMap);
	}

	/**
	 * 软分页
	 * 
	 * @param request
	 *            当前请求
	 * @param content
	 *            软分页内容
	 * @param mark
	 *            分页标记
	 * @return
	 */
	protected String softPage(HttpServletRequest request, String content, String mark) {
		try {
			String page = (String) request.getAttribute(PAGE);
			if (StringUtils.isNumeric(page)) {
				page = request.getParameter(PAGE);
			}
			int currpageNo = 1;
			if (StringUtils.isNumeric(page)) {
				currpageNo = Integer.parseInt(page);
			}
			SoftPagination pagination = new SoftPagination(mark, content, currpageNo);
			SoftPaginationUrl.replaceNav(pagination, request, "copyEntityItem");
			return pagination.getPageContent(currpageNo);
		}
		catch (Exception e) {
			e.printStackTrace();
			return StringUtils.EMPTY;
		}
	}

	/**
	 * 检查SQL注入,返回SQL注入过滤后的字符串
	 * 
	 * @param input
	 *            待检查的字符串
	 * @return 过滤后的字符串
	 */
	protected String sqlIntjectFilt(String input) {
		boolean isSqlIntjection = SqlInjectionFilter.checkSqlInjectionData(input);
		if (isSqlIntjection) {
			log.warn("可能包含sql注入攻击的非法数据:" + input);
			input = SqlInjectionFilter.filterSqlInjectionData(input);
			log.warn("可能包含sql注入攻击的非法数据已经进行过滤处理！");
		}
		return input;
	}

	/**
	 * Convenience method to update a formBean in it's scope
	 * 
	 * @param mapping
	 *            The ActionMapping used to select this instance
	 * @param request
	 *            The HTTP request we are processing
	 * @param form
	 *            The ActionForm
	 */
	protected void updateFormBean(ActionMapping mapping, HttpServletRequest request, ActionForm form) {
		// Remove the obsolete form bean
		if (mapping.getAttribute() != null) {
			if ("request".equals(mapping.getScope())) {
				request.setAttribute(mapping.getAttribute(), form);
			} else {
				HttpSession session = request.getSession();
				session.setAttribute(mapping.getAttribute(), form);
			}
		}
	}

}
